package top.guoziyang.mydb.backend.parser;

import java.util.ArrayList;
import java.util.List;

import top.guoziyang.mydb.backend.parser.statement.Abort;
import top.guoziyang.mydb.backend.parser.statement.Begin;
import top.guoziyang.mydb.backend.parser.statement.Commit;
import top.guoziyang.mydb.backend.parser.statement.Create;
import top.guoziyang.mydb.backend.parser.statement.Delete;
import top.guoziyang.mydb.backend.parser.statement.Drop;
import top.guoziyang.mydb.backend.parser.statement.Insert;
import top.guoziyang.mydb.backend.parser.statement.Select;
import top.guoziyang.mydb.backend.parser.statement.Show;
import top.guoziyang.mydb.backend.parser.statement.SingleExpression;
import top.guoziyang.mydb.backend.parser.statement.Update;
import top.guoziyang.mydb.backend.parser.statement.Where;
import top.guoziyang.mydb.common.Error;

public class Parser {
    /**
     * 实现了一个 SQL-like 语句解析器 的核心方法，用于将输入的字节数组表示的语句解析成对应的语义操作对象（stat），并处理解析过程中可能的错误
     */
    public static Object Parse(byte[] statement) throws Exception {
        Tokenizer tokenizer = new Tokenizer(statement);
        String token = tokenizer.peek(); // 获取当前的第一个 token，用于判断语句的类型
        tokenizer.pop(); // 消耗当前 token，准备解析后续内容

        Object stat = null;
        Exception statErr = null;
        try {
            switch(token) {  //根据 token 的值判断语句类型
                case "begin":
                    stat = parseBegin(tokenizer);
                    break;
                case "commit":
                    stat = parseCommit(tokenizer);
                    break;
                case "abort":
                    stat = parseAbort(tokenizer);
                    break;
                case "create":
                    stat = parseCreate(tokenizer);
                    break;
                case "drop":
                    stat = parseDrop(tokenizer);
                    break;
                case "select":
                    stat = parseSelect(tokenizer);
                    break;
                case "insert":
                    stat = parseInsert(tokenizer);
                    break;
                case "delete":
                    stat = parseDelete(tokenizer);
                    break;
                case "update":
                    stat = parseUpdate(tokenizer);
                    break;
                case "show":
                    stat = parseShow(tokenizer);
                    break;
                default:
                    throw Error.InvalidCommandException;
            }
        } catch(Exception e) {
            statErr = e;
        }
        try {
            String next = tokenizer.peek();
            if(!"".equals(next)) { //查看是否还有剩余的 token
                //如果存在未解析的内容，说明语句不合法，生成错误信息。
                byte[] errStat = tokenizer.errStat();
                statErr = new RuntimeException("Invalid statement: " + new String(errStat));
            }
        } catch(Exception e) {
            e.printStackTrace();
            byte[] errStat = tokenizer.errStat();
            statErr = new RuntimeException("Invalid statement: " + new String(errStat));
        }
        if(statErr != null) { //如果解析未完成或抛出异常，将错误信息记录到 statErr 中，供后续抛出。
            throw statErr;
        }
        return stat;
    }

    /**
     * 解析 show 语句,仅支持简单的 show 命令，不允许有额外参数
     * 例如:输入："show".getBytes() 解析成功，返回 Show 对象。
     * 输入："show tables".getBytes() 抛出 InvalidCommandException，因为不允许有额外参数。
     */
    private static Show parseShow(Tokenizer tokenizer) throws Exception {
        String tmp = tokenizer.peek();
        if("".equals(tmp)) {  //如果返回空字符串（表示没有后续内容），说明语法合法，返回一个空的 Show 对象
            return new Show();
        }
        throw Error.InvalidCommandException;  //如果有多余的内容，说明语法非法，抛出 InvalidCommandException
    }

    /**
     * 解析 update 语句,例如: update table_name set field_name = value [where condition];
     * 解析结果为Update对象：Update {
     *     tableName = "users",
     *     fieldName = "age",
     *     value = "30",
     *     where = Condition { field = "id", operator = "=", value = "1" }
     * }
     */
    private static Update parseUpdate(Tokenizer tokenizer) throws Exception {
        Update update = new Update();
        update.tableName = tokenizer.peek(); //获取第一个 token 作为表名
        tokenizer.pop();

        if(!"set".equals(tokenizer.peek())) { //检查接下来的 token 是否为 set,如果不是，抛出异常
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        update.fieldName = tokenizer.peek(); //获取字段名
        tokenizer.pop();

        if(!"=".equals(tokenizer.peek())) { //检查是否有 =
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        update.value = tokenizer.peek(); // 获取字段的目标值
        tokenizer.pop();

        String tmp = tokenizer.peek();
        if("".equals(tmp)) { //检查是否有 where 子句,如果没有更多 token，where 子句为空
            update.where = null;
            return update;
        }
        // 如果有更多 token，调用 parseWhere 方法解析
        update.where = parseWhere(tokenizer);
        return update;
    }

    /**
     * 解析 delete 语句,例如: delete from table_name [where condition];
     * 解析结果为Delete对象：Delete {
     *     tableName = "users",
     *     where = Condition { field = "age", operator = ">", value = "30" }
     * }
     */
    private static Delete parseDelete(Tokenizer tokenizer) throws Exception {
        Delete delete = new Delete();

        if(!"from".equals(tokenizer.peek())) { //检查接下来的 token 是否为 from
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        String tableName = tokenizer.peek(); //获取表名
        if(!isName(tableName)) {  //调用 isName 方法检查表名是否合法
            throw Error.InvalidCommandException;
        }
        delete.tableName = tableName;
        tokenizer.pop();

        delete.where = parseWhere(tokenizer); //调用 parseWhere 方法解析 where 条件
        return delete;
    }

    /**
     * 解析 insert 语句,例如: INSERT INTO users VALUES 'John', 'Doe', 30
     * Insert {
     *     tableName = "users",
     *     values = ["'John'", "'Doe'", "30"]
     * }
     */
    private static Insert parseInsert(Tokenizer tokenizer) throws Exception {
        Insert insert = new Insert();

        if(!"into".equals(tokenizer.peek())) { //查第一个关键词是否是 into
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        String tableName = tokenizer.peek();
        if(!isName(tableName)) {  //获取表名并验证是否符合命名规则
            throw Error.InvalidCommandException;
        }
        insert.tableName = tableName;
        tokenizer.pop();

        if(!"values".equals(tokenizer.peek())) { //检查接下来的关键字是否是 values
            throw Error.InvalidCommandException;
        }

        List<String> values = new ArrayList<>();
        while(true) { //遍历后续的 token，逐一提取值
            tokenizer.pop();
            String value = tokenizer.peek();
            if("".equals(value)) { //当遇到空字符串（""）时，结束解析
                break;
            } else {
                values.add(value);
            }
        }
        insert.values = values.toArray(new String[values.size()]);

        return insert;
    }

    /**
     * 解析 select 语句
     *支持的语法格式：
     * SELECT field1, field2 FROM table_name [WHERE condition];
     * SELECT * FROM table_name;
     */
    private static Select parseSelect(Tokenizer tokenizer) throws Exception {
        Select read = new Select();

        List<String> fields = new ArrayList<>();
        String asterisk = tokenizer.peek();
        if("*".equals(asterisk)) { //如果 token 是 *，直接将其加入字段列表
            fields.add(asterisk);
            tokenizer.pop();
        } else {
            while(true) { //否则，逐一解析字段名，并通过 , 分隔字段
                String field = tokenizer.peek();
                if(!isName(field)) {
                    throw Error.InvalidCommandException;
                }
                fields.add(field);
                tokenizer.pop();
                if(",".equals(tokenizer.peek())) {
                    tokenizer.pop();
                } else {
                    break;
                }
            }
        }
        read.fields = fields.toArray(new String[fields.size()]);

        if(!"from".equals(tokenizer.peek())) { //检查下一个 token 是否是 from
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        String tableName = tokenizer.peek();
        if(!isName(tableName)) { //获取表名并验证是否符合命名规则
            throw Error.InvalidCommandException;
        }
        read.tableName = tableName;
        tokenizer.pop();

        String tmp = tokenizer.peek();
        if("".equals(tmp)) { //如果没有更多 token，说明没有 where 子句，返回
            read.where = null;
            return read;
        }
        //如果有更多 token，调用 parseWhere 方法解析条件
        read.where = parseWhere(tokenizer);
        return read;
    }

    /**
     * 解析 where 子句,构造并返回一个 Where 对象。
     * 支持以下两种格式：
     * 单一条件：WHERE field = value
     * 复合条件：WHERE field1 = value1 AND field2 = value2
     */
    private static Where parseWhere(Tokenizer tokenizer) throws Exception {
        Where where = new Where();

        if(!"where".equals(tokenizer.peek())) { // 检查是否以 "where" 开始，不是则抛出异常
            throw Error.InvalidCommandException;
        }
        tokenizer.pop(); // 消耗 "where" 关键字

        SingleExpression exp1 = parseSingleExp(tokenizer); //调用 parseSingleExp 方法，解析单一条件表达式（如 field = value）
        where.singleExp1 = exp1;

        String logicOp = tokenizer.peek();
        if("".equals(logicOp)) { // 如果没有后续内容
            where.logicOp = logicOp;   // 逻辑运算符为空
            return where;  // 返回只包含单一条件的 Where 对象
        }
        if(!isLogicOp(logicOp)) {  // 如果有后续内容，检查是否是合法的逻辑运算符
            throw Error.InvalidCommandException;
        }
        where.logicOp = logicOp; // 设置逻辑运算符
        tokenizer.pop(); // 消耗逻辑运算符

        SingleExpression exp2 = parseSingleExp(tokenizer); //调用 parseSingleExp 方法，解析第二个条件表达式
        where.singleExp2 = exp2; //将解析结果存储到 Where 对象的 singleExp2 属性中

        if(!"".equals(tokenizer.peek())) { // 检查是否还有未解析的 token
            throw Error.InvalidCommandException; //如果存在多余的 token，说明语句不合法，抛出异常
        }
        return where;
    }

    /**
     * 解析单一条件表达式,并返回 SingleExpression 对象
     */
    private static SingleExpression parseSingleExp(Tokenizer tokenizer) throws Exception {
        SingleExpression exp = new SingleExpression();

        String field = tokenizer.peek();
        if(!isName(field)) {  //验证字段名是否合法
            throw Error.InvalidCommandException;
        }
        exp.field = field;
        tokenizer.pop();

        String op = tokenizer.peek();
        if(!isCmpOp(op)) { //验证运算符是否合法
            throw Error.InvalidCommandException;
        }
        exp.compareOp = op;
        tokenizer.pop();

        exp.value = tokenizer.peek(); // 获取当前 token，将其作为目标值
        tokenizer.pop();
        return exp;
    }

    /**
     * 检查给定的字符串是否是合法的逻辑运算符
     * 目前仅支持= > 和 <
     */
    private static boolean isCmpOp(String op) {
        return ("=".equals(op) || ">".equals(op) || "<".equals(op));
    }

    /**
     * 检查给定的字符串是否是合法的逻辑运算符
     * 目前仅支持and和or
     */
    private static boolean isLogicOp(String op) {
        return ("and".equals(op) || "or".equals(op));
    }

    /**
     * 解析 DROP 语句，用于删除指定表。
     * 示例: DROP TABLE table_name;
     */
    private static Drop parseDrop(Tokenizer tokenizer) throws Exception {
        if(!"table".equals(tokenizer.peek())) { //检查起始 token 是否是 table
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        String tableName = tokenizer.peek();
        if(!isName(tableName)) { //获取表名，并调用 isName 验证是否符合命名规则
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        if(!"".equals(tokenizer.peek())) { //确保没有多余的 token
            throw Error.InvalidCommandException;
        }

        Drop drop = new Drop();
        drop.tableName = tableName;
        return drop;
    }

    /**
     * 解析 CREATE 语句，用于创建表结构，包括字段和索引
     * 支持的语法格式：
     * CREATE TABLE table_name (field1 type1, field2 type2, ...) INDEX (index1, index2, ...);
     */
    private static Create parseCreate(Tokenizer tokenizer) throws Exception {
        if(!"table".equals(tokenizer.peek())) { //检查起始 token 是否是 table
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();

        Create create = new Create();
        String name = tokenizer.peek();
        if(!isName(name)) {  //获取表名，并调用 isName 验证是否符合命名规则
            throw Error.InvalidCommandException;
        }
        create.tableName = name;

        List<String> fNames = new ArrayList<>();
        List<String> fTypes = new ArrayList<>();
        while(true) { //遍历并解析字段名和字段类型
            tokenizer.pop();
            String field = tokenizer.peek();
            if("(".equals(field)) {
                break;
            }

            if(!isName(field)) { //检查字段是否符合命名规则（通过 isName）
                throw Error.InvalidCommandException;
            }

            tokenizer.pop();
            String fieldType = tokenizer.peek();
            if(!isType(fieldType)) { //检查字段类型是否合法（通过 isType）
                throw Error.InvalidCommandException;
            }
            fNames.add(field);
            fTypes.add(fieldType);
            tokenizer.pop();

            String next = tokenizer.peek();
            if(",".equals(next)) {
                continue;
            } else if("".equals(next)) {
                throw Error.TableNoIndexException;
            } else if("(".equals(next)) {
                break;
            } else {
                throw Error.InvalidCommandException;
            }
        }
        create.fieldName = fNames.toArray(new String[fNames.size()]);
        create.fieldType = fTypes.toArray(new String[fTypes.size()]);

        tokenizer.pop();
        if(!"index".equals(tokenizer.peek())) { //验证关键字 index 是否存在
            throw Error.InvalidCommandException;
        }

        List<String> indexes = new ArrayList<>();
        while(true) { //遍历并解析索引字段名，确保其符合命名规则
            tokenizer.pop();
            String field = tokenizer.peek();
            if(")".equals(field)) {
                break;
            }
            if(!isName(field)) {
                throw Error.InvalidCommandException;
            } else {
                indexes.add(field);
            }
        }
        create.index = indexes.toArray(new String[indexes.size()]);
        tokenizer.pop();

        if(!"".equals(tokenizer.peek())) { //确保没有多余的 token
            throw Error.InvalidCommandException;
        }
        return create;
    }

    /**
     * 用于判断输入的字符串是否是合法的数据类型
     */
    private static boolean isType(String tp) {
        return ("int32".equals(tp) || "int64".equals(tp) ||
        "string".equals(tp));
    }

    /**
     * 解析 abort 命令，用于终止事务
     */
    private static Abort parseAbort(Tokenizer tokenizer) throws Exception {
        if(!"".equals(tokenizer.peek())) {
            throw Error.InvalidCommandException;
        }
        return new Abort();
    }

    /**
     * 解析 commit 命令，用于提交事务
     */
    private static Commit parseCommit(Tokenizer tokenizer) throws Exception {
        if(!"".equals(tokenizer.peek())) {
            throw Error.InvalidCommandException;
        }
        return new Commit();
    }

    /**
     * 解析 begin 命令，用于启动事务
     * 支持的语法格式：
     * BEGIN;
     * BEGIN ISOLATION LEVEL READ COMMITTED;
     * BEGIN ISOLATION LEVEL REPEATABLE READ;
     */
    private static Begin parseBegin(Tokenizer tokenizer) throws Exception {
        String isolation = tokenizer.peek();
        Begin begin = new Begin();
        if("".equals(isolation)) { //如果 token 流为空，直接返回一个默认的 Begin 对象。
            return begin;
        }
        //验证 token 是否为 isolation 和 level
        if(!"isolation".equals(isolation)) {
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();
        String level = tokenizer.peek();
        if(!"level".equals(level)) {
            throw Error.InvalidCommandException;
        }
        tokenizer.pop();
        //解析支持的隔离级别,根据隔离级别设置 Begin 对象的 isRepeatableRead 属性
        String tmp1 = tokenizer.peek();
        if("read".equals(tmp1)) {
            tokenizer.pop();
            String tmp2 = tokenizer.peek();
            if("committed".equals(tmp2)) {
                tokenizer.pop();
                if(!"".equals(tokenizer.peek())) {
                    throw Error.InvalidCommandException;
                }
                return begin;
            } else {
                throw Error.InvalidCommandException;
            }
        } else if("repeatable".equals(tmp1)) {
            tokenizer.pop();
            String tmp2 = tokenizer.peek();
            if("read".equals(tmp2)) {
                begin.isRepeatableRead = true;
                tokenizer.pop();
                if(!"".equals(tokenizer.peek())) {
                    throw Error.InvalidCommandException;
                }
                return begin;
            } else {
                throw Error.InvalidCommandException;
            }
        } else {
            throw Error.InvalidCommandException;
        }
    }

    /**
     * 判断一个字符串是否是合法的标识符（如表名或字段名）
     */
    private static boolean isName(String name) {
        return !(name.length() == 1 && !Tokenizer.isAlphaBeta(name.getBytes()[0]));
    }
}
